/*
 * Copyright (c) 2017 深圳市高德威技术有限公司  All rights reserved.
 *
 * utils.c
 *
 *  Created on: 2017年3月21日
 *      Author: chenshisheng
 */

#include "utils.h"
#include "ctimer.h"



// 在链接脚本内定义的内存的BSS段及DATA段的地址范围变量
extern unsigned int  __bss_start__, __bss_end__;
extern unsigned int __data_start__, __data_end__;

#define CSS_START_ADDR  ((void *) & __bss_start__)
#define CSS_END_ADDR    ((void *) & __bss_end__)
#define DATA_START_ADDR ((void *) & __data_start__)
#define DATA_END_ADDR   ((void *) & __data_end__)



static void _DelayInit(void);
static void _CrcConfig(uint8_t poly);
static void _LedInit(void);

static __IO uint32_t _delayCounter;
static __IO Timer_Tick_t _timerCounter;
static uint8_t _crc8Poly;

void Utils_Init(void)
{
    _timerCounter = 0;

    _DelayInit();
    _LedInit();

    /* Configure the CRC peripheral to use the polynomial x8 + x7 + x6 + x4 + x2 + 1 */
    _CrcConfig(0xd5);
}

static void _LedInit(void)
{
    // 指示灯 引脚
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    Utils_SetLed(Utils_Led_0, 1);
    Utils_DelayMs(1000);
    Utils_SetLed(Utils_Led_0, 0);
}

void Utils_SetLed(Utils_Led_t led, int on)
{
    if(led != Utils_Led_0)
    {
        return;
    }

//    GPIO_WriteBit(GPIOB, GPIO_Pin_8, on ? Bit_SET : Bit_RESET);
    if(on)
    {
        GPIOB->BSRR = GPIO_Pin_8;
    }
    else
    {
        GPIOB->BRR = GPIO_Pin_8;
    }
}

void Utils_TriggerLed(Utils_Led_t led)
{
    if(led != Utils_Led_0)
    {
        return;
    }

    GPIOB->ODR ^= GPIO_Pin_8;
}

static void _DelayInit(void)
{
    _delayCounter = 0;

    if(SysTick_Config(SystemCoreClock / UTILS_SYSTICK_FREQ))
    {
      /* Capture error */
      while (1);
    }

}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
    _timerCounter += 1;

  if(_delayCounter != 0)
  {
      _delayCounter -= 1;
  }

  Ctimer_TickUpdate();
}

Timer_Tick_t Utils_Time(void)
{
    Timer_Tick_t tick;

    // 数据复制过程中，_timerCounter 有可能
    // 因SYSTICK中断而变化
    do
    {
        tick = _timerCounter;
    }while(tick != _timerCounter);

    return tick;
}

void Utils_DelayMs(unsigned int ms)
{
    _delayCounter = ms;
    while(_delayCounter != 0)
    {
//        PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);
    }
}

/**
  * @brief  Configure CRC peripheral to use 8-bit polynomials
  * @param  poly: the CRC polynomial
  * @retval None
  */
static void _CrcConfig(uint8_t poly)
{
    _crc8Poly = poly;
}

/**
  * @brief  Compute CRC value for input message
  * @param  data: pointer at uint8_t
  * @param  size: the size of the input message
  * @retval The computed CRC value
  */
uint8_t Utils_Crc8BitsCompute(const void *data, uint32_t size)
{
    uint8_t crc = 0x00;
    const uint8_t *vdata;
    int bit;

    vdata = data;
    while (size--)
    {
        crc ^= *vdata++;
        for (bit = 0; bit < 8; bit++)
        {
            if (crc & 0x80)
            {
                crc = (crc << 1) ^ _crc8Poly;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

/**
 * @判断一个变量是不是全局变量
 * @param varAddr 变量的地址（指针）
 * @return TRUE 是全局变量
 *         FALSE 不是全局变量
 */
bool Utils_IsGlobalVariable(void *varAddr)
{
    if((varAddr < CSS_START_ADDR) && (varAddr > CSS_END_ADDR) &&
            (varAddr < DATA_START_ADDR) && (varAddr > DATA_END_ADDR))
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}
